package net.sf.filelink.preferences;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import net.sf.filelink.FileLinkPlugin;
import net.sf.filelink.utl.QueryUtils;

import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.viewers.ColumnLayoutData;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.eclipse.ui.dialogs.ContainerSelectionDialog;

/**
 * This class represents a preference page that is contributed to the Preferences dialog. By subclassing
 * <samp>FieldEditorPreferencePage</samp>, we can use the field support built into JFace that allows us to create a
 * page that is small and knows how to save, restore and apply itself.
 * <p>
 * This page is used to modify preferences only. They are stored in the preference store that belongs to the main
 * plug-in class. That way, preferences can be accessed directly via the preference store.
 */

public class MainPreferencePage extends PreferencePage implements IWorkbenchPreferencePage {

    private Button m_addFolderButton;

    private Button m_removeFolderButton;

    private TableViewer m_folderTableViewer;

    private final String[] m_initFolderArray;

    /**
     * constructor for HoverPreferencePage
     */
    public MainPreferencePage() {
        m_initFolderArray = QueryUtils.getSearchFolderPaths();
    }

    /**
     * Button listener that delegates for widget selection events.
     */
    private final SelectionAdapter buttonListener = new SelectionAdapter() {
        @Override
        public void widgetSelected(SelectionEvent event) {
            if (event.widget == m_addFolderButton) {
                addSearchFolder();
            } else if (event.widget == m_removeFolderButton) {
                removeSearchFolder(m_folderTableViewer);
            }
        }
    };

    private final FolderContentProvider m_contentProvider = new FolderContentProvider();

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.jface.preference.PreferencePage#createContents(org.eclipse.swt.widgets.Composite)
     */
    @Override
    protected Control createContents(Composite parent) {

        Font font = parent.getFont();

        Composite top = new Composite(parent, SWT.NONE);
        top.setFont(font);

        GridLayout layout = new GridLayout();
        layout.numColumns = 2;
        top.setLayout(layout);
        GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
        top.setLayoutData(gridData);

        Label label = new Label(top, SWT.NONE);
        GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
        gd.horizontalSpan = 2;
        label.setLayoutData(gd);
        label.setFont(font);
        label.setText("Search scope");

        m_folderTableViewer = createTableViewer(top);
        m_folderTableViewer.setInput(m_initFolderArray);

        createButtonGroup(top);
        return top;
    }

    protected void removeSearchFolder(TableViewer fileTableViewer) {

        List<String> folders = new ArrayList<String>();
        folders.addAll(getSearchFolders());
        IStructuredSelection sel = (IStructuredSelection) fileTableViewer.getSelection();
        Object[] array = sel.toArray();
        folders.removeAll(Arrays.asList(array));

        m_folderTableViewer.setInput(folders);
    }

    protected void addSearchFolder() {
        ContainerSelectionDialog dialog = new ContainerSelectionDialog(m_folderTableViewer.getControl().getShell(),
                null, true, null);
        dialog.open();
        Object[] result = dialog.getResult();
        if (result != null && result.length == 1) {
            List<String> folders = new ArrayList<String>();
            folders.addAll(getSearchFolders());
            folders.add(((IPath) result[0]).toPortableString());
            m_folderTableViewer.setInput(folders);
        }
    }

    /**
     * Creates and returns a configured table viewer in the given parent
     */
    private TableViewer createTableViewer(Composite parent) {
        Table table = new Table(parent, SWT.MULTI | SWT.FULL_SELECTION | SWT.BORDER);
        GridData data = new GridData(GridData.FILL_BOTH);
        int availableRows = availableRows(parent);
        data.heightHint = table.getItemHeight() * (availableRows / 10);
        data.widthHint = IDialogConstants.ENTRY_FIELD_WIDTH;
        table.setLayoutData(data);
        table.setFont(parent.getFont());

        TableViewer tableViewer = new TableViewer(table);

        tableViewer.setContentProvider(m_contentProvider);
        tableViewer.setLabelProvider(new LabelProvider());

        TableLayout tableLayout = new TableLayout();
        table.setLayout(tableLayout);
        table.setHeaderVisible(true);
        table.setLinesVisible(true);

        String[] tableColumnHeaders = { "Folder" };

        ColumnLayoutData[] tableColumnLayouts = { new ColumnWeightData(100), };

        for (int i = 0; i < tableColumnHeaders.length; i++) {
            tableLayout.addColumnData(tableColumnLayouts[i]);
            TableColumn column = new TableColumn(table, SWT.NONE, i);
            column.setResizable(tableColumnLayouts[i].resizable);
            column.setText(tableColumnHeaders[i]);
        }

        return tableViewer;
    }

    /**
     * Return the number of rows available in the current display using the current font.
     * 
     * @param parent
     *            The Composite whose Font will be queried.
     * @return The result of the display size divided by the font size.
     */
    private int availableRows(Composite parent) {
        int fontHeight = (parent.getFont().getFontData())[0].getHeight();
        int displayHeight = parent.getDisplay().getClientArea().height;
        return displayHeight / fontHeight;
    }

    /**
     * Creates the group which will contain the buttons.
     */
    private void createButtonGroup(Composite top) {
        Composite buttonGroup = new Composite(top, SWT.NONE);
        GridLayout layout = new GridLayout();
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        buttonGroup.setLayout(layout);
        buttonGroup.setLayoutData(new GridData(GridData.FILL_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL));
        buttonGroup.setFont(top.getFont());

        addButtonsToButtonGroup(buttonGroup);
    }

    /*
     * (non-Javadoc)
     */
    protected void addButtonsToButtonGroup(Composite parent) {
        m_addFolderButton = createPushButton(parent, "Add folder");
        m_removeFolderButton = createPushButton(parent, "Remove folder");
    }

    /**
     * Creates and returns a configured button in the given composite with the given label. Widget selection callbacks
     * for the returned button will be processed by the <code>buttonListener</code>
     */
    private Button createPushButton(Composite parent, String label) {
        Button button = new Button(parent, SWT.PUSH);
        button.setFont(parent.getFont());
        if (label != null) {
            button.setText(label);
        }

        button.addSelectionListener(buttonListener);
        GridData gridData = new GridData(GridData.VERTICAL_ALIGN_BEGINNING | GridData.FILL_HORIZONTAL);
        button.setLayoutData(gridData);
        return button;
    }

    public List<String> getSearchFolders() {
        return m_contentProvider.getAllElements();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
     */
    public void init(IWorkbench workbench) {

    }

    private static class FolderContentProvider implements IStructuredContentProvider {

        List<String> elements = new ArrayList<String>();

        public void addElements(String folderPath) {
            elements.add(folderPath);
        }

        public Object[] getElements(Object inputElement) {
            return elements.toArray();
        }

        public List<String> getAllElements() {
            return elements;
        }

        public void dispose() {
        }

        @SuppressWarnings("unchecked")
        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
            elements.clear();
            if (newInput != null) {
                List<String> list;
                if (newInput instanceof List) {
                    list = (List<String>) newInput;
                } else {
                    list = Arrays.asList((String[]) newInput);
                }
                elements.addAll(list);
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.jface.preference.PreferencePage#performOk()
     */
    @Override
    public boolean performOk() {

        StringBuffer folders = new StringBuffer();
        for (String folder : getSearchFolders()) {
            folders.append(folder);
            folders.append(',');
        }

        IPreferenceStore store = FileLinkPlugin.getDefault().getPreferenceStore();
        store.setValue(PreferenceConstants.PREFERENCE_FOLDERS, folders.toString());

        FileLinkPlugin.getDefault().savePluginPreferences();
        return super.performOk();
    }

}